//
//  ScanViewController.swift
//  ZZUI
//
//  Created by 张文晏 on 2018/11/20.
//  Copyright © 2018 张文晏. All rights reserved.
//

import UIKit
import AVFoundation
import SnapKit

public class ScanViewController: UIViewController {
    
    public enum AnalyseResult {
        case success(finishClosure: (() -> Void))
        case failure(msg: String)
    }
    
    // MARK: - Subviews
    let borderImageView = UIImageView(image: NCUIBundle.image("ui_scan_border"))
    let lineImageView = UIImageView(image: NCUIBundle.image("ui_scan_line"))
    let topView = UIView()
    let leadingView = UIView()
    let bottomView = UIView()
    let trailingView = UIView()
    
    
    // MARK: - Variables
    /// 扫描线移动定时器
    var timer: Timer?
    var lineCurrentY = CGFloat(0)
    let session = AVCaptureSession()
    
    public lazy var analyseClosure: ((_ code: String) -> AnalyseResult) = { code in
        if code.count > 10 {
            return .success(finishClosure: {
                self.navigationController?.popViewController(animated: true)
            })
        } else {
            return .failure(msg: "不能解析的字符串")
        }
    }
    
    
    // MARK: - View controller
    override public func viewDidLoad() {
        super.viewDidLoad()
        setupNavigationBar()
        setupUI()
        setupScanDevice()
    }
    
    override public func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if !session.isRunning {
            session.startRunning()
        }
    }
    
    // MARK: - Setup
    func setupNavigationBar() {
        navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
        navigationController?.navigationBar.isTranslucent = true
        navigationController?.navigationBar.tintColor = .white
        navigationController?.navigationBar.shadowImage = UIImage()
    }
    
    func setupUI() {
        view.backgroundColor = .white
        view.addSubview(borderImageView)
        borderImageView.snp.makeConstraints { make in
            make.top.equalTo(165)
            make.centerX.equalToSuperview()
            make.width.height.equalTo(254)
        }
        
        borderImageView.addSubview(lineImageView)
        lineImageView.frame = CGRect.init(x: 0, y: 0, width: 254, height: 3)
        
        view.addSubview(topView)
        topView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.bottom.equalTo(borderImageView.snp.top)
        }
        topView.backgroundColor = UIColor(white: 0, alpha: 0.3)
        
        view.addSubview(leadingView)
        leadingView.snp.makeConstraints { make in
            make.top.bottom.equalTo(borderImageView)
            make.leading.equalToSuperview()
            make.trailing.equalTo(borderImageView.snp.leading)
        }
        leadingView.backgroundColor = UIColor(white: 0, alpha: 0.3)
        
        view.addSubview(bottomView)
        bottomView.snp.makeConstraints { make in
            make.top.equalTo(borderImageView.snp.bottom)
            make.leading.bottom.trailing.equalToSuperview()
        }
        bottomView.backgroundColor = UIColor(white: 0, alpha: 0.3)
        
        view.addSubview(trailingView)
        trailingView.snp.makeConstraints { make in
            make.top.bottom.equalTo(borderImageView)
            make.leading.equalTo(borderImageView.snp.trailing)
            make.trailing.equalToSuperview()
        }
        trailingView.backgroundColor = UIColor(white: 0, alpha: 0.3)
    }
    
    func setupScanDevice() {
        guard let device = AVCaptureDevice.default(for: .video) else { return }
        guard let input = try? AVCaptureDeviceInput(device: device) else {
            HUD.showMessage("请在\"设置\"中打开\"新核云\"的相机权限")
            navigationController?.popViewController(animated: true)
            return
        }
        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: .main)
        session.sessionPreset = UIScreen.main.bounds.height < 500 ? .vga640x480 : .high
        session.addInput(input)
        session.addOutput(output)
        output.metadataObjectTypes = [
            .qr, .ean13, .ean8, .code128, .code39, .code93, .code39Mod43,
            .pdf417, .aztec, .upce, .interleaved2of5, .itf14, .dataMatrix
        ]
        /// 计算中间可探测区域
        var scanRect = CGRect(
            x: (UIScreen.main.bounds.width - 254) / 2,
            y: 165,
            width: 254,
            height: 254
        )
        
        /*
         设 有效区域为
         validRect = CGRectMake(x, y, w, h);
         预览图层的frame为
         preViewRect = CGRectMake(0, 0, kScreenW, kScreenH);
         那么
         rectOfInterest = CGRectMake(y / kScreenH, (kScreenW-(w+x)) / kScreenW, h / kScreenH, w / kScreenW);
         
         作者：S型身材的猪
         链接：https://www.jianshu.com/p/8bb3d8cb224e
         來源：简书
         简书著作权归作者所有，任何形式的转载都请联系作者获得授权并注明出处。
         */
        // 计算 rect of interest, 注意 x, y 交换位置
        scanRect = CGRect(
            x: scanRect.origin.y / UIScreen.main.bounds.height,
            y: (UIScreen.main.bounds.width - (scanRect.width + scanRect.origin.x)) / UIScreen.main.bounds.width,
            width: scanRect.height / UIScreen.main.bounds.height,
            height: scanRect.width / UIScreen.main.bounds.width
        )
        // 计算可探测区域
        output.rectOfInterest = scanRect
        /// 输出预览 Layer
        let previewLayer = AVCaptureVideoPreviewLayer(session: session)
        previewLayer.videoGravity = .resizeAspectFill
        previewLayer.frame = UIScreen.main.bounds
        view.layer.insertSublayer(previewLayer, at: 0)
        // 开启探测并显示动画
        session.startRunning()
        startAnimation()
    }
    
    // MARK: - Actions
    func analyseCode(_ code: String) {
        print("scaned code is \(code)")
        let result = analyseClosure(code)
        session.stopRunning()
        stopAnimation()
        switch result {
        case .success(let finishClosure):
            finishClosure()
        case .failure(let msg):
            showCannotRecognizedCode(message: msg)
        }
    }
    
    func showCannotRecognizedCode(message: String = "不能识别的二维码") {
        let vc = UIAlertController(title: nil, message: "不能识别的二维码", preferredStyle: .alert)
        let goOnAction = UIAlertAction(title: "继续扫描", style: .default) { _ in
            self.session.startRunning()
            self.startAnimation()
        }
        vc.addAction(goOnAction)
        present(vc, animated: true)
    }
    
    @objc func lineAnimation() {
        lineCurrentY += 1
        if lineCurrentY > borderImageView.bounds.height - lineImageView.bounds.height {
            lineCurrentY = 0
        }
        var frame = lineImageView.frame
        frame.origin.y = lineCurrentY
        UIView.animate(withDuration: 0.01) {
            self.lineImageView.frame = frame
        }
    }
    
    func startAnimation() {
        timer = .scheduledTimer(
            timeInterval: 0.01,
            target: self,
            selector: #selector(lineAnimation),
            userInfo: nil,
            repeats: true
        )
        RunLoop.main.add(timer!, forMode: .common)
        timer?.fire()
    }
    
    func stopAnimation() {
        guard let tm = timer else { return }
        if tm.isValid {
            tm.invalidate()
            timer = nil
        }
    }
    
    deinit {
        print("ScanViewController - deinit")
    }
}

// MARK: - AVCaptureMetadataOutputObjectsDelegate
extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate {
    public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        /// 扫描数据
        guard let data = metadataObjects.first as? AVMetadataMachineReadableCodeObject else {
            return
        }
        /// 扫描到的字符串
        guard let strValue = data.stringValue else { return }
        analyseCode(strValue)
    }
}
